﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BFlatCompile.Nodes
{
	// TODO: apply return null to end of Setter if last statement is not return
	public class Property : IClassMember, ICodeContainer
	{
		public string Name { get; private set; }
		public int NameIndex { get { return Variable.Table.GetId(this.Name); } }
		public string Filename { get; private set; }
		public string FullSignature
		{
			get
			{
				return this.owningClass.FullName + "." + this.Name;
			}
		}

		private Class owningClass;

		public bool IsStatic { get; private set; }
		public Executable[] Getter { get; private set; }
		public Executable[] Setter { get; private set; }
		public int GetterID { get; set; }
		public int SetterID { get; set; }

		private Property(string name, bool isStatic, Executable[] getter, Executable[] setter, string filename)
		{
			Variable.Table.Register(name);
			this.Name = name;
			this.Filename = filename;
			this.IsStatic = isStatic;

			if (getter != null)
			{
				getter = Executable.AppendReturnIfNecessary(new List<Executable>(getter));
			}

			if (setter != null)
			{
				setter = Executable.AppendReturnIfNecessary(new List<Executable>(setter));
			}

			this.Getter = getter;
			this.Setter = setter;
		}

		public static Property Parse(Tokens tokens)
		{
			bool isStatic = tokens.PopIfPresent("static");
			bool isAbstract = tokens.PopIfPresent("abstract");
			Token token = tokens.PopExpected("property");
			string filename = token.RelativeFile;
			string name = tokens.PopIdentifier();
			tokens.PopExpected("{");

			Executable[] getter = null;
			Executable[] setter = null;

			for (int i = 0; i < 2; ++i)
			{
				bool isEtterAbstract = tokens.PopIfPresent("abstract");

				if (tokens.PopIfPresent("get"))
				{
					if (getter == null)
					{
						getter = CodeBlock.Parse(tokens, true);
					}
					else
					{
						throw new ParserException("Cannot declare two getters in the same property.", tokens.PreviousToken());
					}
				}

				if (tokens.PopIfPresent("set"))
				{
					if (setter == null)
					{
						setter = CodeBlock.Parse(tokens, true);
					}
					else
					{
						throw new ParserException("Cannot declare two setters in the same property.", tokens.PreviousToken());
					}
				}
			}

			tokens.PopExpected("}");

			return new Property(name, isStatic, getter, setter, filename);
		}

		public string SignaturePrefix
		{
			get { throw new NotImplementedException(); }
		}

		public void ResolveCode(Class c, Dictionary<object, object> parents)
		{
			this.owningClass = c;
			foreach (Executable exec in Util.GetExecutables(this.Getter, this.Setter))
			{
				exec.ResolveCode(c, parents);
			}
		}

		public void ResolveClassToThis(Class c)
		{
			if (this.IsStatic)
			{
				foreach (Executable exec in Util.GetExecutables(this.Getter, this.Setter))
				{
					exec.ResolveClassToThis(c);
				}
			}
		}
	}
}
